package org.richin.script.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.richin.lang.util.ObjectUtils;
import org.richin.lang.util.StringUtils;
import org.richin.reflection.util.ReflectUtils;

/**
 * Dom 帮助类
 *
 * @author poyexinghun
 * @version 2009-02-11
 */
public class XmlHelper {

        private static final String ELEMENT_TYPE = "type";

        private static final String STRING = "java.lang.String";

        private static final String LIST = "java.util.ArrayList";

        /**
         * get object of document
         *
         * @param path
         * @return Document
         * @throws Exception
         */
        public Document getDocument(String path) throws Exception {
                return getDocument(new File(path));
        }

        /**
         * get object of document
         *
         * @param file
         * @return Document
         * @throws Exception
         */
        public Document getDocument(File file) throws Exception {
                return getDocument(new FileInputStream(file));
        }

        /**
         * get object of document
         *
         * @param inputStream
         * @return Document
         * @throws Exception
         */
        public Document getDocument(InputStream inputStream) throws Exception {
                return getDocument(new InputStreamReader(inputStream));
        }

        /**
         * get object of document
         *
         * @param reader
         * @return Document
         * @throws Exception
         */
        public Document getDocument(Reader reader) throws Exception {
                if (reader==null) {
                        return null;
                }
                SAXReader saxReader = new SAXReader();
                return saxReader.read(reader);
        }

        /**
         * get type of current element
         *
         * @param element
         * @return String
         */
        public String getElementType(Element element) {
                String elementType = STRING;
                // 判断子标签是否有属性
                if (element.attributes().size() > 0) {
                        elementType = element.attributeValue(ELEMENT_TYPE);
                        if (StringUtils.isEmpty(elementType)) {
                                elementType = STRING;
                        }
                        return elementType;
                }
                // 判断子标签是否有下级标签
                if (element.elements().size() > 0) {
                        elementType = LIST;
                        return elementType;
                }
                return elementType;
        }

        /**
         *  after iterator child element will append object of element to collection
         *
         * @param element
         * @param object
         * @return List
         * @throws Exception
         */
        public void iteratorElementToList(Element element, List<Object> list)
                        throws Exception {
                // 迭代子标签
                for (Iterator it = element.elementIterator(); it.hasNext();) {
                        Element elementChild = (Element) it.next();
                        String elementType = getElementType(elementChild);
                        if (elementType.equals(STRING)) {
                                String newObject = elementChild.getTextTrim();
                                list.add(newObject);
                        } else if (elementType.equals(LIST)) {
                                List newObject = (List) ObjectUtils.getObject(elementType);
                                iteratorElementToList(elementChild, newObject);
                                list.add(newObject);
                        } else {
                                Object newObject = ObjectUtils.getObject(elementType);
                                iteratorElementToObject(elementChild, newObject);
                                list.add(newObject);
                        }
                }
        }

        /**
         * 迭代子标签,并将子标签信息载入到对象
         *
         * @param element
         * @param object
         */
        public void iteratorElementToObject(Element element, Object object)
                        throws Exception {
                Map<String, Object> fieldsMap = ReflectUtils.getFeildsInfo(object);
                // 获得对象属性名称
                String[] fieldsName = (String[])fieldsMap.get(ReflectUtils.FIELDS_NAME);
                // 获得对象属性类型
                // 属性的个数
                int length = fieldsName.length;

                // 添加子标签的属性值到对象
                iteratorAttributeToObject(element, object, fieldsName);

                // 添加子标签的子标签值到对象
                for (Iterator it = element.elementIterator(); it.hasNext();) {
                        Element elementChild = (Element) it.next();
                        String elementType = getElementType(elementChild);
                        String elementChildName = elementChild.getName();

                        if (elementType.equals(STRING)) {
                                String elementChildText = elementChild.getTextTrim();
                                for (int j = 0; j < length; j++) {
                                        if (elementChildName.equalsIgnoreCase(fieldsName[j])) {
                                        	ReflectUtils.setMethodValue(object, "set",
                                                                fieldsName[j], elementChildText);
                                                break;
                                        }
                                }
                        } else if (elementType.equals(LIST)) {
                                List elementChilds = (List) ObjectUtils.getObject(elementType);
                                iteratorElementToList(elementChild, elementChilds);
                                for (int j = 0; j < length; j++) {
                                        if (elementChildName.equalsIgnoreCase(fieldsName[j])) {
                                        	ReflectUtils.setMethodValue(object, "set",
                                                                fieldsName[j], elementChilds);
                                                break;
                                        }
                                }
                        } else {
                                Object elementObject = ObjectUtils.getObject(elementType);
                                iteratorElementToObject(elementChild, elementObject);
                                for (int j = 0; j < length; j++) {
                                        if (elementChildName.equalsIgnoreCase(fieldsName[j])) {
                                                ReflectUtils.setMethodValue(object, "set",
                                                                fieldsName[j], elementObject);
                                                break;
                                        }
                                }
                        }
                }
        }

        /**
         * 迭代标签的属性,并把属性的值赋给对象
         *
         * @param object
         * @param attributeList
         * @param fieldsName
         * @return Object
         */
        public void iteratorAttributeToObject(Element element, Object object,
                        String[] fieldsName) throws Exception {
                int length = fieldsName.length;
                String name = element.getName();

                // 判断标签的名称是否和类的名称相同
                if (object.getClass().getSimpleName().equalsIgnoreCase(name)) {
                        for (Iterator ait = element.attributeIterator(); ait.hasNext();) {
                                Attribute attribute = (Attribute) ait.next();
                                String attributeName = attribute.getName();
                                String attributeValue = attribute.getValue();
                                for (int j = 0; j < length; j++) {
                                        if (attributeName.equalsIgnoreCase(fieldsName[j])) {
                                        	ReflectUtils.setMethodValue(object, "set",
                                                                fieldsName[j], attributeValue);
                                                break;
                                        }
                                }
                        }
                }
        }

        /**
         * save object to document
         *
         * @param object
         * @param element
         */
        public void saveObjectToDom(Object object, Element element)
                        throws Exception {
                Map<String, Object> fieldsMap = ReflectUtils.getFeildsInfo(object);
                // 获得对象属性名称
                String[] fieldsName = (String[])fieldsMap.get(ReflectUtils.FIELDS_NAME);
                // 属性的个数
                int length = fieldsName.length;

                Element elementChild = element.addElement(object.getClass()
                                .getSimpleName().toLowerCase());
                elementChild.addAttribute(ELEMENT_TYPE, object.getClass().getName());
                for (int i = 0; i < length; i++) {
                        Element elementChildChild = elementChild.addElement(fieldsName[i]);
                        Object elementChildChildValue = ReflectUtils.getMethodValue(object,
                                        "get", fieldsName[i]);
                        if (elementChildChildValue instanceof String) {
                                elementChildChild.addText((String) elementChildChildValue);
                        }
                        if (elementChildChildValue instanceof List) {
                                saveListToDom(fieldsName[i], (List) elementChildChildValue,
                                                elementChildChild);
                        }
                }
        }

        /**
         * save collection to document
         *
         * @param elementName
         * @param list
         * @param element
         */
        public void saveListToDom(String elementName, List list, Element element) {
                for (Object object : list) {
                        if (object instanceof String) {
                                if (elementName.substring(elementName.length() - 1).equals("s")) {
                                        String elementChildName = elementName.substring(0,
                                                        elementName.length() - 1);
                                        Element elementChild = element.addElement(elementChildName);
                                        elementChild.addText((String) object);
                                }
                        }
                }
        }

        /**
         * 保存对象到document
         *
         * @param document
         * @param filePath
         * @throws Exception
         */
        public void saveDom(Object object, String filePath) throws Exception {
                // 创建document
                Document document = DocumentHelper.createDocument();
                // 添加根元素到document
                String rootElementName = object.getClass().getSimpleName()
                                .toLowerCase()
                                + "s";
                Element rootElement = document.addElement(rootElementName);
                // 保存对象中的数据到document
                saveObjectToDom(object, rootElement);
                // 创建格式化输出流
                OutputFormat format = OutputFormat.createPrettyPrint();
                // 将document保存为本地文件
                XMLWriter writer = new XMLWriter(new FileWriter(new File(filePath)),
                                format);
                writer.write(document);
                writer.close();
        }

        /**
         * 批量保存对象到document
         *
         * @param list
         * @param filePath
         * @throws Exception
         */
        public void batchSaveDom(List list, String filePath) throws Exception {
                // 创建document
                Document document = DocumentHelper.createDocument();
                Object object = list.size() > 0 ? list.get(0) : null;
                // 添加根元素到document
                String rootElementName = object.getClass().getSimpleName()
                                .toLowerCase()
                                + "s";
                Element rootElement = document.addElement(rootElementName);
                // 保存对象中的数据到document
                for (Object obj : list) {
                        saveObjectToDom(obj, rootElement);
                }
                // 创建格式化输出流
                OutputFormat format = OutputFormat.createPrettyPrint();
                // 将document保存为本地文件
                XMLWriter writer = new XMLWriter(new FileWriter(new File(filePath)),
                                format);
                writer.write(document);
                writer.close();
        }

        /**
         * 更新对象到document
         *
         * @param object
         * @return
         */
        public void updateDom(Object object, String filePath) throws Exception {
                // 获得document
                Document document = getDocument(filePath);
                // 获得根元素
                Element rootElement = document.getRootElement();
                // 保存对象中的数据到document
                saveObjectToDom(object, rootElement);
                // 创建格式化输出流
                OutputFormat format = OutputFormat.createPrettyPrint();
                // 将修改过的document保存为本地文件
                XMLWriter writer = new XMLWriter(new FileWriter(new File(filePath)),
                                format);
                writer.write(document);
                writer.close();
        }

        /**
         * 批量更新对象到document
         *
         * @param list
         * @param filePath
         * @throws Exception
         */
        public void batchUpdateDom(List list, String filePath) throws Exception {
                // 获得document
                Document document = getDocument(filePath);
                // 获得根元素
                Element rootElement = document.getRootElement();
                // 保存对象中的数据到document
                for (Object object : list) {
                        saveObjectToDom(object, rootElement);
                }
                // 创建格式化输出流
                OutputFormat format = OutputFormat.createPrettyPrint();
                // 将修改过的document保存为本地文件
                XMLWriter writer = new XMLWriter(new FileWriter(new File(filePath)),
                                format);
                writer.write(document);
                writer.close();
        }

        /**
         * 获得document对象集合
         *
         * @param filePath
         * @return List
         * @throws Exception
         */
        public List getObjects(String filePath) throws Exception {
                Document document = getDocument(filePath);
                if (document==null) {
                        return null;
                }
                Element rootElement = document.getRootElement();
                List objects = new ArrayList();
                iteratorElementToList(rootElement, objects);
                return objects;
        }

}
